﻿using System;
using System.Net;

using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using System.IO;
using Tulde.Core;



namespace Tulde.MP3tunes
{
    public abstract class BaseDataService<T> : IDataService<T>
    {
        
        protected abstract string BaseUrl { get; }


        #region IDataService<T> Members

        public virtual Uri CreateServiceEndpoint(T operation, ServiceParameters parameters)
        {
            return new Uri(this.AppendParametersToUrl(this.BaseUrl, operation.ToString(), parameters), UriKind.Absolute);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="uri"></param>
        /// <param name="callback"></param>
        /// <param name="error"></param>
        public virtual void ExecuteAsync<T1>(Uri uri, Action<T1> callback, Action<Exception> error = null)
        {
            if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
            {
                System.Net.WebClient authClient = new WebClient();
                authClient.DownloadStringCompleted += (sender, e) =>
                {
                    string result = String.Empty;
                    try
                    {
                        result = e.Result;
                        T1 instance = this.DeserializeResult<T1>(result);
                        if (callback != null)
                            callback(instance);
                    }
                    catch (Exception ex)
                    {
                        if (error != null)
                            error(ex);
                    }

                };
                authClient.DownloadStringAsync(uri, new DataTransportPair { Callback = callback, Uri = uri });

            }
            else
            {
                if (error != null)
                    error(new System.Net.WebException("Unable to establish a network connection"));
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="operation"></param>
        /// <param name="parameters"></param>
        /// <param name="callback"></param>
        /// <param name="error"></param>
        public virtual void ExecuteAsync<T1>(T operation, ServiceParameters parameters, Action<T1> callback, Action<Exception> error)
        {
            if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
            {
                Uri uri = CreateServiceEndpoint(operation, parameters);

                System.Net.WebClient authClient = new WebClient();
                authClient.DownloadStringCompleted += (sender, e) =>
                    {
                        string result = String.Empty;
                        try
                        {
                            result = e.Result;
                            T1 instance = this.DeserializeResult<T1>(result);
                            if(callback!=null)
                                callback(instance);
                        }
                        catch (Exception ex)
                        {
                            if( error!=null)
                                error(ex);
                        }

                    };

                authClient.DownloadStringAsync(uri);
            }
            else
            {
                if( error!=null)
                    error(new System.Net.WebException("Unable to establish a network connection"));
            }
        }
       
        protected abstract object DeserializeResult(string result);
        protected  virtual T1 DeserializeResult<T1>(string result)
        {
            if (!string.IsNullOrEmpty(result))
                return ViewModelSerializerFactory.Instance.Deserialize<T1>(result);
            else
            {
                return Activator.CreateInstance<T1>();
            }
        }
       

        protected virtual string AppendParametersToUrl(string url, string operation, ServiceParameters parameters)
        {
            List<string> parametersList = new List<string>();
            foreach (string key in parameters.Keys)
            {
                parametersList.Add(String.Format("{0}={1}", key, parameters.GetParameter(key)));
            }
            if (parameters == null || !parameters.Keys.Any())
            {
                return url;
            }
            else
            {
                return url + operation + "?" + String.Join("&", parametersList.ToArray());
            }
        }

        #endregion
    }

    public class DataServiceEventArgs : EventArgs
    {
        public int State { get; set; }
        public string Message { get; set; }
        public string Title { get; set; }
    }
    internal class DataTransportPair
    {
        public object Callback { get; set; }
        public object Uri { get; set; }
    }
}
